package com.lanyou.esb.cook.proxy.auth.processor.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;

import com.lanyou.esb.cook.proxy.auth.processor.AcquireAuthProcessor;
import com.lanyou.esb.cook.proxy.common.Constants;
import com.lanyou.esb.cook.proxy.common.SystemResCode;
import com.lanyou.esb.cook.proxy.exception.AuthException;
import com.lanyou.esb.cook.proxy.meta.AuthType;
import com.lanyou.esb.cook.proxy.meta.IfType;
import com.lanyou.esb.cook.proxy.service.impl.TraceLogServiceImpl;

/**
 * SOAP请求类型，默认获取校验信息处理器 <br>
 * 
 * 描述：<br>
 * 示例：<br>
 * <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
 * xmlns:web="http://WebXml.com.cn/"><br>
 * <soap:Header><br>
 * <web:EsbHead><br>
 * <CallSystemCode>请求方系统编码</CallSystemCode><br>
 * <ApplyKey>密钥</ApplyKey><br>
 * <AccessToken>访问令牌</AccessToken><br>
 * </web:EsbHead><br>
 * </soap:Header><br>
 * <soap:Body><br>
 * <web:getRegionProvince/><br>
 * </soap:Body><br>
 * </soap:Envelope><br>
 * 目标是取出以上示例报文的：<web:EsbHead>。。。</web:EsbHead>这里面的信息
 * 
 * @author Davey.wu
 */
public class DefaultSoapAcquireAuthProcessor implements AcquireAuthProcessor {
	@Override
	public AuthType getAuthType() {
		return AuthType.OAUTH;
	}

	@Override
	public IfType getIfType() {
		return IfType.WS;
	}

	@Override
	public Map<String, Object> acquire(HttpServletRequest request,
			String content, Map<String, Boolean> parameters)
			throws AuthException, Exception {
		if (parameters == null || parameters.size() == 0) {
			return new HashMap<String, Object>(0);
		}
		// 获取核验信息
		Map<String, String> authInfo = getAuthInfo(content, parameters);
		if (authInfo == null || authInfo.isEmpty()) {
			if (TraceLogServiceImpl.isTrace()) {
				// 记录跟踪日志
				TraceLogServiceImpl
						.addTraceLog(Constants.MSG_AUTHINFO_FORMAT_ERROR);
			}
			// 认证信息格式不正确
			throw new AuthException(SystemResCode.MSG_AUTHINFO_FORMATE_ERROR,
					SystemResCode.CODE_AUTHINFO_FORMATE_ERROR);
		}
		Map<String, Object> map = new HashMap<>(2);
		// 参数名
		String paraName = "";
		// 参数值
		String paraValue = "";
		// 参数是否必需
		boolean isAquired = false;
		for (Map.Entry<String, Boolean> entry : parameters.entrySet()) {
			paraName = entry.getKey();
			isAquired = entry.getValue();
			paraValue = authInfo.get(paraName);
			// 参数符合条件，加入结果集中
			if (!isAquired || StringUtils.isNotBlank(paraValue)) {
				map.put(paraName, paraValue);
				continue;
			}
			// 缺少参数为必需，抛出异常 start==============================
			// 缺少调用方系统编码
			if (Constants.CALL_SYSTEM_CODE.equals(paraName)) {
				if (TraceLogServiceImpl.isTrace()) {
					// 记录跟踪日志
					TraceLogServiceImpl.addTraceLog(
							SystemResCode.MSG_CALL_SYSTEM_EMPTY,
							Constants.FLAG_LEFT_SQUARE_BRACKET, paraName,
							Constants.FLAG_EQUAL, paraValue,
							Constants.FLAG_RIGHT_SQUARE_BRACKET);
				}
				throw new AuthException(SystemResCode.MSG_CALL_SYSTEM_EMPTY,
						SystemResCode.CODE_CALL_SYSTEM_EMPTY);
			}
			// 缺少访问令牌
			if (Constants.ACCESS_TOKEN.equals(paraName)) {
				if (TraceLogServiceImpl.isTrace()) {
					// 记录跟踪日志
					TraceLogServiceImpl.addTraceLog(
							SystemResCode.MSG_ACCESSTOKEN_EMPTY,
							Constants.FLAG_LEFT_SQUARE_BRACKET, paraName,
							Constants.FLAG_EQUAL, paraValue,
							Constants.FLAG_RIGHT_SQUARE_BRACKET);
				}
				throw new AuthException(SystemResCode.MSG_ACCESSTOKEN_EMPTY,
						SystemResCode.CODE_ACCESSTOKEN_EMPTY);
			}
			// 缺少密钥
			if (Constants.APPLY_KEY.equals(paraName)) {
				if (TraceLogServiceImpl.isTrace()) {
					// 记录跟踪日志
					TraceLogServiceImpl.addTraceLog(
							SystemResCode.MSG_APPLYKEY_EMPTY,
							Constants.FLAG_LEFT_SQUARE_BRACKET, paraName,
							Constants.FLAG_EQUAL, paraValue,
							Constants.FLAG_RIGHT_SQUARE_BRACKET);
				}
				throw new AuthException(SystemResCode.MSG_APPLYKEY_EMPTY,
						SystemResCode.CODE_APPLYKEY_EMPTY);
			}

			// 其它必需参数缺失,记录跟踪日志
			if (TraceLogServiceImpl.isTrace()) {
				// 记录跟踪日志
				TraceLogServiceImpl.addTraceLog(paraName,
						Constants.MSG_IS_EMPTY,
						Constants.FLAG_LEFT_SQUARE_BRACKET, paraName,
						Constants.FLAG_EQUAL, paraValue,
						Constants.FLAG_RIGHT_SQUARE_BRACKET);
			}
			throw new AuthException(paraName + Constants.MSG_IS_EMPTY, "0");
			// 缺少参数为必需，抛出异常 end==============================
		}
		return map;
	}

	/**
	 * 解析认证信息
	 * 
	 * @param content
	 *            ：请求报文
	 * @return
	 */
	private Map<String, String> getAuthInfo(String content,
			Map<String, Boolean> parameters) {
		if (StringUtils.isBlank(content)) {
			return null;
		}
		// 模式匹配规则
		Pattern pattern = Pattern.compile("<(((?!:).)*:)?\\s*"
				+ Constants.PROXY_HEADER + ".*>.*</(((?!:).)*:)?\\s*"
				+ Constants.PROXY_HEADER + "\\s*>");
		Matcher matches = pattern.matcher(content);
		if (!matches.find()) {
			return null;
		}

		Map<String, String> map = new HashMap<>(3);
		String subStr = matches.group(0);
		// 去掉头部，取目标信息
		subStr = subStr.substring(subStr.indexOf(">") + 1,
				subStr.lastIndexOf("<"));
		for (Entry<String, Boolean> entry : parameters.entrySet()) {
			String key = entry.getKey();
			int start = subStr.indexOf(key);
			if (start < 0) {
				// 不存在开头KEY，忽略这个KEY
				continue;
			}
			start = subStr.indexOf(">", start);
			if (start < 0) {
				// 格式不正确，忽略这个KEY
				continue;
			}
			start += 1;
			int end = subStr.indexOf("<", start);
			if (end < 0) {
				// 不存在结束标识，忽略这个KEY
				continue;
			}
			int haveEnd = subStr.indexOf(key, end);
			if (haveEnd < 0) {
				// 不存在KEY结束标识，忽略这个KEY
				continue;
			}
			String value = subStr.substring(start, end);
			if (value == null) {
				value = "";
			}
			map.put(key, value.trim());
		}

		return map;
	}

	// private String getAuthInfoFromSoap(String content, String parameter)
	// throws Exception {
	//
	// String value = null;
	// // // 解析SOAP协议
	// // MessageFactory msgFactory = MessageFactory.newInstance();
	// // SOAPMessage reqMsg = msgFactory.createMessage(new MimeHeaders(),
	// // request.getInputStream());
	// // SOAPBody body = reqMsg.getSOAPBody();
	// // // 从soapheader中抽取认证信息
	// // SOAPHeader soapHeader = reqMsg.getSOAPHeader();
	// // if (soapHeader != null) {
	// // value = parse(soapHeader.getChildElements(), parameter);
	// // }
	// // // applyKey = parse(elements);
	// // if (StringUtils.isEmpty(value) && body != null) {
	// // value = parse(body.getChildElements(), parameter);
	// // }
	// // return value;
	//
	// value = formateSoapMsg(content, parameter);
	// return value;
	// }
	//
	// private String formateSoapMsg(String soap, String key) {
	// String result = "";
	// if (StringUtils.isBlank(soap) || StringUtils.isBlank(key)) {
	// return "";
	// }
	// Pattern pattern = Pattern.compile("<(((?!:).)*:)?\\s*" + key
	// + ".*>.*</(((?!:).)*:)?\\s*" + key + "\\s*>");
	// Matcher matches = pattern.matcher(soap);
	// if (matches.find()) {
	// String subStr = matches.group(0);
	// Matcher matcherLv2 = Pattern.compile(">.*<").matcher(subStr);
	// if (matcherLv2.find()) {
	// subStr = matcherLv2.group(0);
	// result = subStr.substring(1, subStr.length() - 1);
	// }
	// }
	// return result;
	// }
	//
	// private String parse(Iterator<Object> iterator, String parameter) {
	// if (iterator == null) {
	// return "";
	// }
	// SOAPTextImpl nextSoapTextImpl;
	// SOAPElement nextSoapElement;
	// String name = "";
	// String value = "";
	// while (iterator.hasNext()) {
	// Object next = iterator.next();
	// Class<? extends Object> classes = next.getClass();
	// if (next instanceof SOAPElement) {
	// nextSoapElement = (SOAPElement) next;
	// // TODO name or local name or qr name?
	// name = nextSoapElement.getLocalName();
	// if (parameter.equals(name)) {
	// return nextSoapElement.getTextContent();
	// }
	// value = parseSoapElement(nextSoapElement.getChildElements(),
	// parameter);
	// if (!StringUtils.isEmpty(value)) {
	// return value;
	// }
	// } else {// if (next instanceof SOAPTextImpl) {
	// try {
	// nextSoapTextImpl = ((SOAPTextImpl) next);
	// } catch (Exception e) {
	// e.printStackTrace();
	// return null;
	// }
	// name = nextSoapTextImpl.getNodeName();
	// if (parameter.equals(name)) {
	// return nextSoapTextImpl.getTextContent();
	// }
	// NodeList list = nextSoapTextImpl.getChildNodes();
	// value = parseSoapTextImpl(nextSoapTextImpl.getChildNodes(),
	// parameter);
	// if (!StringUtils.isEmpty(value)) {
	// return value;
	// }
	// }
	//
	// }
	// return "";
	// }
	//
	// private String parseSoapElement(Iterator<SOAPElement> iterator,
	// String parameter) {
	// if (iterator == null) {
	// return "";
	// }
	// SOAPElement next;
	// String name = "";
	// String value = "";
	// while (iterator.hasNext()) {
	// next = iterator.next();
	// // TODO name or local name or qr name?
	// name = next.getLocalName();
	// if (parameter.equals(name)) {
	// return next.getTextContent();
	// }
	// value = parse(next.getChildElements(), parameter);
	// if (!StringUtils.isEmpty(value)) {
	// return value;
	// }
	// }
	//
	// return "";
	// }
	//
	// private String parseSoapTextImpl(NodeList nodeList, String parameter) {
	// if (nodeList == null || nodeList.getLength() <= 0) {
	// return "";
	// }
	// Node next;
	// String name = "";
	// String value = "";
	// for (int i = 0; i < nodeList.getLength(); ++i) {
	// next = nodeList.item(i);
	// name = next.getLocalName();
	// if (parameter.equals(name)) {
	// return next.getTextContent();
	// }
	// value = parseSoapTextImpl(next.getChildNodes(), parameter);
	// if (!StringUtils.isEmpty(value)) {
	// return value;
	// }
	// }
	// return "";
	// }

	// public static void main(String[] args) {
	// String content =
	// "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:web=\"http://WebXml.com.cn/\">"
	// + " <soap:Header>"
	// + "        <web:EsbHead>"
	// + "               <CallSystemCode>请求方系统编码</CallSystemCode>"
	// + "              <ApplyKey>密钥</ApplyKey>"
	// + "             <AccessToken>访问令牌</AccessToken>"
	// + "      </web:EsbHead>"
	// + "   </soap:Header>"
	// + "  <soap:Body>"
	// + "    <web:getRegionProvince/>"
	// + "   </soap:Body>" + " </soap:Envelope>";
	//
	// DefaultSoapAcquireAuthProcessor processor = new
	// DefaultSoapAcquireAuthProcessor();
	// Map<String, String> map = processor.getAuthInfo(content,
	// ParamFactory.getParameter4Oauth());
	// for (Entry<String, String> entry : map.entrySet()) {
	// System.out.println(entry.getKey() + ":" + entry.getValue());
	// }
	// }
}
